#include "stdafx.h"
#include "TestApplication.h"
#include "ChunkDebugMesh.h"
#include "chunkmanager.h"
#include "D3DRenderer.h"

#include "AppTestCamera.h"

/*
#include <direct.h>

#include <Common/Base/hkBase.h>
#include <Common/Base/Memory/System/Util/hkMemoryInitUtil.h>
#include <Common/Base/Memory/Allocator/Malloc/hkMallocAllocator.h>

// Physics
#include <Physics/Dynamics/World/hkpWorld.h>
#include <Physics/Collide/Dispatch/hkpAgentRegisterUtil.h>

// Visual Debugger includes
#include <Common/Visualize/hkVisualDebugger.h>
#include <Physics/Utilities/VisualDebugger/hkpPhysicsContext.h>			

#include <Common/Visualize/hkProcess.h>
#include <Common/Visualize/hkProcessRegisterUtil.h>
#include <Common/Visualize/hkProcessFactory.h>
#include <Common/Visualize/Process/hkDebugDisplayProcess.h>
*/

using namespace ChunkSystem;

TestApplication::TestApplication()
	:m_pChunkCamera(NULL),m_bShowScapemap(true)//,m_pVDB(NULL),m_fPhysicsStepFrequency( 1.0f / 60.0f )
{
}

TestApplication::~TestApplication()
{
	/*
	if( m_pVDB != NULL )
		delete m_pVDB;
		*/

	if( m_pChunkCamera != NULL )
		delete m_pChunkCamera;
}

TestCamera* TestApplication::GetCamera(void)
{
	return m_pChunkCamera;
}

bool TestApplication::Init(IDirect3DDevice9* pd3dDevice)
{
	//create space
	ChunkManager::GetInstance().ChangeChunkSpace("test_chunkspace");

	//set resource path
	ChunkManager::GetInstance().SetResPath( "D:\\development\\exercise\\Application\\TestApplication\\TestApplication" );
	ChunkManager::GetInstance().SetSpacePath( "test_chunkspace" );

	//create camera
	TestCameraFactory camFactory;
	m_pChunkCamera = static_cast<TestCamera*>( ChunkManager::GetInstance().GetChunkCamera(&camFactory) );

	// Setup the camera
	//m_pChunkCamera->SetEnableYAxisMovement( false );
	m_pChunkCamera->SetRotateButtons( false, false, true );
	m_pChunkCamera->SetScalers( 0.01f, 50.0f );


	D3DXVECTOR3 vecEye( 0.0f, 2.0f, 0.0f );
	D3DXVECTOR3 vecAt ( 0.0f, 2.0f, 1.0f );

	m_pChunkCamera->SetViewParams( &vecEye, &vecAt );

	//create renderer
	IRenderer* pRenderer = new D3DRenderer(pd3dDevice,m_pChunkCamera);
	ChunkManager::GetInstance().SetRenderer(pRenderer);

	pd3dDevice->SetRenderState( D3DRS_CULLMODE , D3DCULL_NONE );
	pd3dDevice->SetRenderState( D3DRS_LIGHTING , FALSE );

	//init air scape
	if( !m_AirScape.Init(pd3dDevice) )
		return false;

	/*
	//init vdb
	hkpWorld* pPhysicsWorld = ChunkManager::GetInstance().GetCurPhysicsWorld();
	assert( pPhysicsWorld != NULL );

	hkArray<hkProcessContext*> contexts;
	// <PHYSICS-ONLY>: Register physics specific visual debugger processes
	// By default the VDB will show debug points and lines, however some products such as physics and cloth have additional viewers
	// that can show geometries etc and can be enabled and disabled by the VDB app.
	hkpPhysicsContext* context;
	{
		// The visual debugger so we can connect remotely to the simulation
		// The context must exist beyond the use of the VDB instance, and you can make
		// whatever contexts you like for your own viewer types.
		context = new hkpPhysicsContext();
		hkpPhysicsContext::registerAllPhysicsProcesses(); // all the physics viewers
		context->addWorld(pPhysicsWorld); // add the physics world so the viewers can see it

		contexts.pushBack(context);
	}

	m_pVDB = new hkVisualDebugger(contexts);
	m_pVDB->serve();
	*/

	return true;
}

void TestApplication::OnReset(IDirect3DDevice9* pd3dDevice)
{
	if(!m_AirScape.Reset(pd3dDevice))
		assert( false );
}

void TestApplication::OnFrameMove(float fElapsedTime)
{
	//update frame
	if( m_pChunkCamera == NULL )
		return;
	m_pChunkCamera->FrameMove(fElapsedTime);

	m_AirScape.UpdateCamera( m_pChunkCamera->GetEyePt() );

	//tick manager
	ChunkManager::GetInstance().Tick();

	/*
	hkpWorld* pPhysicsWorld = ChunkManager::GetInstance().GetCurPhysicsWorld();
	if( pPhysicsWorld == NULL )
		return;

	pPhysicsWorld->stepDeltaTime( m_fPhysicsStepFrequency );

	m_pVDB->step( m_fPhysicsStepFrequency );
	*/
}

void TestApplication::OnMsg(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
	bool* pbNoFurtherProcessing, void* pUserContext)
{
	if( m_pChunkCamera != NULL )
		m_pChunkCamera->HandleMessages( hWnd, uMsg, wParam, lParam );

	//handle app events
	switch( uMsg )
    {
	case WM_KEYDOWN:
		{
			switch( wParam )
			{
			case 'M':
				{
					m_bShowScapemap = !m_bShowScapemap;
				}
				break;
			case VK_ADD:
				{
					float fScaler = m_pChunkCamera->GetMoveSpeed();
					fScaler += 10.f;
					fScaler = fScaler > 150.0f ? 150.0f : fScaler;

					m_pChunkCamera->SetScalers( 0.01f, fScaler );
				}
				break;
			case VK_SUBTRACT:
				{
					float fScaler = m_pChunkCamera->GetMoveSpeed();
					fScaler -= 10.f;
					fScaler = fScaler < 5.0f ? 5.0f : fScaler;

					m_pChunkCamera->SetScalers( 0.01f, fScaler );
				}
				break;

			default:
				break;
			}
        }
		default:
			break;
	}

}

void TestApplication::OnRenderScene(IDirect3DDevice9* pd3dDevice)
{
	if( pd3dDevice == NULL )
		return;

	const D3DXMATRIX* matChunkCameraView  = m_pChunkCamera->GetViewMatrix();
	const D3DXMATRIX* matChunkCameraProject = m_pChunkCamera->GetProjMatrix();

	pd3dDevice->SetTransform( D3DTS_VIEW, matChunkCameraView );
	pd3dDevice->SetTransform( D3DTS_PROJECTION, matChunkCameraProject );

	ChunkManager::GetInstance().Draw();

	if( m_bShowScapemap )
	{
		AirScapeCamera camera = m_AirScape.GetCamera();
		const D3DXMATRIX* matAirScapeView  = camera.GetViewMatrix();
		const D3DXMATRIX* matAirScapeProject = camera.GetProjMatrix();
		pd3dDevice->SetTransform( D3DTS_VIEW, matAirScapeView );
		pd3dDevice->SetTransform( D3DTS_PROJECTION, matAirScapeProject );

		//Render bird scape
		if( !m_AirScape.Draw(pd3dDevice,m_pChunkCamera) )
			assert(false);
	}
}
